#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <cassert>
#include "Protocol.hpp"
#include "Sock.hpp"

using namespace std;
using namespace ns_protocol;

#define BUFFER_SIZE 1024

void *send(void *args) // 发送线程
{
    int sock = *(int *)args; // 获取sock

    string message; // 发送缓冲区
    while (true)
    {
        // 1. 获取需求
        Request req;
        std::cout << "Please Enter # ";
        std::cin >> req._x >> req._op >> req._y;

        // 2. 序列化
        std::string reqString = req.Serialize();
        reqString = Encode(reqString); // 添加报头
        Send(sock, reqString);
    }
}

void *recv(void *args) // 获取到服务器信息和sock
{
    int sock = *(int *)args; // 获取sock
    string buffer;
    while (true)
    {
        bool res = Recv(sock, &buffer);
        if (!res)
        {
            cout << "server quit" << endl;
            exit(0);
        }
        string respString = Decode(buffer); // 根据报头，拆分出一个完整的请求报文
        if (respString.empty())
            continue; // 没有完整报文，回去重读

        // 走到这里说明肯定有一个完整的请求报文了
        Response resp;
        resp.DeSerialized(respString);
        string err;
        switch (resp._code)
        {
        case 1:
            err = "除0错误";
            break;
        case 2:
            err = "模0错误";
            break;
        case 3:
            err = "非法操作";
            break;
        case 0:
            break;
        default:
            err = "未知错误";
            break;
        }
        if (!err.empty())
            cout << err << endl;
        else
            printf("%d %c %d = %d\n", resp._x, resp._op, resp._y, resp._result);
    }
}

void Usage(const char *proc)
{
    cout << "Usage: " << proc << " Server_ip Server_port" << endl;
}

//./client 127.0.0.1 8080
int main(int argc, const char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    Sock s;

    // 1.创建Socket
    int sock = s.Socket();
    assert(sock > 0);

    // 2.系统会自动给客户端绑定ip和端口号

    // 3.连接到服务器connect
    s.Connect(sock, argv[1], htons(atoi(argv[2])));

    // 4.发送线程和接收线程
    pthread_t send_thread, recv_thread;

    pthread_create(&send_thread, NULL, send, (void *)&sock);
    pthread_create(&recv_thread, NULL, recv, (void *)&sock); // 启动收发线程

    pthread_join(send_thread, NULL);
    pthread_join(recv_thread, NULL); // 等待线程退出

    return 0;
}